
const Ret = require("../Ret"),
{ RequestAuth } = require("../RequestAuth") ,
UUID = require("uuid") ,
AppError = require("../../AppError")

const secert = process.env.session_secert || "password.sanchi.tech"
const Auth = new RequestAuth( secert )
const tokenName = Auth.tokenName()
const expireValue = global.sessionExpire || 60 * 60    //s

function token( uid , group , expire ){
let payload = {
    group : group ,
    token : uid ,
    time :  new Date().getTime() + ( expire || expireValue ) * 1000
}
return Auth.token( payload )
}

function getData( token ){
const payload = Auth.data( token ) 
const expTime = payload.time 
if( (new Date().getTime()) > expTime )
throw new AppError(63 , "无效授权")
return payload
}

async function session( client , group , data , expire ){
expire = expire || expireValue 
const uid = UUID.v1()
const _token = token( uid , group , expire )
//sotre 异步不需要验证
await client.setAsync( uid , data , "EX" ,expire ) 
return _token 
}

async function modifySession( client , uid , data , expire ){
return await client.setAsync( uid , data , "EX" , expire )
}

async function getSession( client , token , group ){
const payload = getData( token )
if( group ){
    if( payload.group != group )
    throw new AppError( 66 , "无效请求权限" ) 
}
const uid = payload.token 
if( !uid )
    throw new AppError(61 , "非法授权")
const data = await client.getAsync( uid )
if( !data )
    throw new AppError( 62 , "授权已过期，请重新授权" )
return {
    payload : payload , 
    data : data 
}
}

async function refreshSession( client , payload ){
const uid = payload.token 
const group = payload.group 
await client.expireAsync( uid , expireValue )
return token( uid , group )
}

function getAuth( ctx ){
const method = ctx.request.method.toUpperCase()
const path = ctx.request.path  
const uri = method + " " + path 
try{
    return ctx.app._Router[ uri ].auth 
}catch(e){
    return null 
}
}

function writeToken( ctx , from , token ){
//是否刷新权限
if( from == "cookie"){
    ctx.cookies.set( tokenName , token )
}else if( from == "header"){
    ctx.response.set( tokenName , token )
}

}

module.exports = async function(ctx , next ){
const auth = getAuth( ctx )
const redis = ctx.Kit.redis 
//TODO auth未加载
if( auth ){
    //提取Token
    const from = auth.from 
    const group = auth.group 
    const token = auth.getToken( ctx )
    if( !token ){
        ctx.body = Ret.err(65 , "无效权限")
        return 
    }

    const ret = await getSession( redis , token , group )
    ctx.request.payload = ret.payload 
    ctx.request.session = ret.data 
    await next()
    let newToken 
    //重新写入session
    if( ctx.session ){
        let sessionData = ret.data
        //set 直接覆盖
        if( ctx.session.set ){
            sessionData = ctx.session.set 
        }
        //append 追加
        if( ctx.session.append ){
            sessionData = Object.assign( sessionData , ctx.session.append )
        }

        //delete 删除某个key
        if( ctx.session.delete ){
            //array 
            const tmp = ctx.session.delete 
            for( let index in tmp ){
                const key = tmp[ index ]
                delete sessionData[ key ]
            }
        }
        //回写session
        newToken = await modifySession( redis , ret.payload.token , sessionData )
    }else{
        newToken = await refreshSession( redis , ret.payload  )
    }
    
    writeToken( ctx , from , newToken )
}else await next()  //无权限配置直接放行

if( ctx.session ){
    if( ctx.session.new ){
        //重新产生Token , 需要包含 from , group , data 三个字段
        const { from , group , data } = ctx.session.new 
        const token = await session( redis , group , data )
        writeToken( ctx , from , token )
    }
}

}